﻿#pragma once


#include "Thread.h"


namespace df
{

	using namespace sdf;
#if defined(_WIN32) || defined(_WIN32_WCE)

#include <winsock2.h>
#include <windows.h>


	// #if defined(__has_include)
	// #	if __has_include(<netinet/tcp.h>)
	// #		include<netinet/tcp.h>
	// #	endif
	// #endif

#ifdef _MSC_VER 
#	if defined(_WIN32_WCE)
#		pragma comment( lib, "ws2.lib" )
#	else
#		pragma comment( lib, "Ws2_32" )
#	endif
#endif

#else

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>	
#include <netdb.h>
#include <errno.h>
#include <netinet/tcp.h>
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) ||  \
	defined(__DragonflyBSD__)
#include <sys/endian.h>
#elif defined(__APPLE__)
#include <machine/endian.h>
#elif defined(sun)
#include <sys/isa_defs.h>
#else
#include <endian.h>
#endif

#endif

	class Net
	{
	private:
		int socket_ = 0;
	public:

		inline operator bool() const
		{
			return socket_ > 0;
		}

		int GetSocket()  const
		{
			return socket_;
		}

		void Close()
		{
			if (socket_ <= 0)
				return;
#if defined(_WIN32) || defined(_WIN32_WCE)
			closesocket(socket_);
#else
			close(socket_);
#endif
			socket_ = 0;
		}

		void Shutdown()
		{
			shutdown(socket_, 2);
			Close();
		}


		static void IpV4ToStr(int32_t ip, String &str)
		{
			uint8_t * ips = (uint8_t *)&ip;
			str << ips[0] << tt_('.') << ips[1] << tt_('.') << ips[2] << tt_('.') << ips[3];
		}

		static String IpV4ToStr(int32_t ip)
		{
			String str;
			IpV4ToStr(ip, str);
			return str;
		}

		static Net CreateTcpSocket()
		{
			Net s;
			for (int i = 0; i < 4; i++)
			{
				s.socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
				if (s.socket_ > 0)
					break;

				if (s.socket_ == 0) {
					DF_LOG("socket 返回 0");
				}
			}
			return s;
		}

		static Net CreateUdpSocket()
		{
			Net s;
			for (int i = 0; i < 4; i++)
			{
				s.socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
				if (s.socket_ > 0)
					break;

				if (s.socket_ == 0) {
					DF_LOG("socket 返回 0");
				}
			}
			return s;
		}

		//链接指定主机
		static Net Connect(const df::CCa & host, uint16_t port, int32_t & ipOut, int timeOut = 0, df::ErrWrap err = nullptr)
		{
			Init();



			struct hostent *server_host;
			if ((server_host = gethostbyname(host.char_)) == NULL)
			{
				DF_LASTERR(err, host << tcc_(" 域名解析失败!"));
				return Net();
			}

			ipOut = *((int32_t*)server_host->h_addr_list[0]);

			struct sockaddr_in server_addr;
			memcpy((void *)&server_addr.sin_addr,
				(void *)server_host->h_addr,
				server_host->h_length);

			server_addr.sin_family = AF_INET;
			server_addr.sin_port = htons(port);


			Net s = CreateTcpSocket();
			if (!s)
			{
				DF_LASTERR(err, host << tcc_(" socket打开失败!"));
				return Net();
			}

			if (timeOut > 0)
				s.SetSendTimeOut(timeOut);
			if (connect(s.socket_, (struct sockaddr *) &server_addr,
				sizeof(server_addr)) < 0)
			{
				DF_LASTERR(err, host << tcc_(" 连接失败!"));
				s.Close();
				return Net();
			}

			return s;
		}

		static Net Connect(const df::CCa & host, uint16_t port, int timeOut = 0, df::ErrWrap err = nullptr)
		{
			int32_t ipOut;
			return Connect(host, port, ipOut, timeOut, err);
		}

		

		//监听指定端口返回socket
		static Net BindListen(uint16_t port, df::ErrWrap err = nullptr)
		{
			DF_ASSERT(port != 0);

			Init();


			Net s = CreateTcpSocket();
			if (!s)
			{
				DF_LASTERR(err, port << tcc_(" socket打开失败!"));
				return Net();
			}


			//填充连接信息
			struct sockaddr_in server_addr;
			server_addr.sin_family = AF_INET;    //通信协议ipv4
			server_addr.sin_addr.s_addr = INADDR_ANY;
			server_addr.sin_port = htons(port);   //端口

			if (bind(s.socket_, (struct sockaddr *) &server_addr,
				sizeof(server_addr)) < 0)
			{
				DF_LASTERR(err, port << tcc_("TCP端口绑定失败!"));
				s.Close();
				return Net();
			}

			if (listen(s.socket_, SOMAXCONN) != 0)
			{
				DF_LASTERR(err, port << tcc_("TCP端口监听失败!"));
				s.Close();
				return Net();
			}

			return s;
		}

		bool Accept(Net & clientSocket, uint32_t & clientIp)
		{
			DF_ASSERT(socket_ > 0);

			struct sockaddr_in client_addr;

#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) ||  \
	defined(_SOCKLEN_T_DECLARED)
			socklen_t n = (socklen_t) sizeof(client_addr);
#else
			int n = (int) sizeof(client_addr);
#endif
			clientSocket.socket_ = accept(socket_, (struct sockaddr *)
				&client_addr, &n);

			if (clientSocket.socket_ < 0)
			{
				return false;
			}
			clientIp = client_addr.sin_addr.s_addr;

			return true;
		}

		bool IsConnected()
		{

			if (socket_ == 0)
				return false;

			int optval=0, optlen = sizeof(int);
#ifdef WIN32
			getsockopt(socket_, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen);
#else
			getsockopt(socket_, SOL_SOCKET, SO_ERROR, (char*)&optval, (socklen_t*)&optlen); 
#endif
			if (optval != 0)
				return false;

#ifdef TCP_INFO
			struct tcp_info info;
			int len = sizeof(info);
			getsockopt(socket_, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
			if ((info.tcpi_state != TCP_ESTABLISHED))
				return false;
#endif

			return true;
		}

		bool CheckLinkStatus()
		{
#ifdef MSG_DONTWAIT
			char msg[1] = { 0 };
			int err = 0;
			err = recv(socket_, msg, sizeof(msg), MSG_DONTWAIT | MSG_PEEK);
			/* client already close connection. */
			if (err == 0 || (err < 0 && errno != EAGAIN))
				return false;
#endif
			return true;
		}

		//返回值:小于0失败,等于0套接字需关闭,大于0传输字节数
		int Recv(void * buf, int len) const
		{
			//DF_ASSERT(len > 0);

#if defined(_WIN32) || defined(_WIN32_WCE)
			int ret = recv(socket_, (char*)buf, len, 0);
#else
			int ret = recv(socket_, buf, len,0);
#endif

			return ret;
		}

		//返回值:小于0失败,等于0套接字需关闭,大于0传输字节数
		int Send(const void * buf, int len)
		{
			DF_ASSERT(len > 0);

#if defined(_WIN32) || defined(_WIN32_WCE)
			int ret = send(socket_, (char*)buf, len, 0);
#else
			int ret = send(socket_, buf, len,0);
#endif

			return ret;
		}

		/** \brief 设置阻塞Recv超时值
		 *
		 * \param sec int 单位:秒
		 * \return int
		 *
		 */
		int SetRecvTimeOut(int sec)
		{
			DF_ASSERT(socket_ > 0);
			DF_ASSERT(sec > 0);

			struct timeval ti;
#if defined(_WIN32) || defined(_WIN32_WCE)
			ti.tv_sec = sec * 1000;
			ti.tv_usec = 0;
#else
			ti.tv_sec = sec;
			ti.tv_usec = 0;
#endif
			return setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, (char*)&ti, sizeof(ti));
		}

		int SetSendBufSize(int size)
		{
			DF_ASSERT(socket_ > 0);
			DF_ASSERT(size >= 0);

			return setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, (char*)&size, sizeof(size));
		}

		int SetRecvBufSize(int size)
		{
			DF_ASSERT(socket_ > 0);
			DF_ASSERT(size > 0);

			return setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, (char*)&size, sizeof(size));
		}


		inline int SetNoDelay(bool on)
		{
			DF_ASSERT(socket_ > 0);
			const char chOpt = on ? 1 : 0;
			return setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (char*)&chOpt, sizeof(chOpt));
		}

		int SetSendTimeOut(int sec)
		{
			DF_ASSERT(socket_ > 0);
			DF_ASSERT(sec > 0);

			struct timeval ti;
#if defined(_WIN32) || defined(_WIN32_WCE)
			ti.tv_sec = sec * 1000;
			ti.tv_usec = 0;
#else
			ti.tv_sec = sec;
			ti.tv_usec = 0;
#endif
			return setsockopt(socket_, SOL_SOCKET, SO_SNDTIMEO, (char*)&ti, sizeof(ti));
		}

		




		static bool Init()
		{
#if defined(_WIN32) || defined(_WIN32_WCE)
			static bool no = true;

			if (no)
			{
				WSADATA wsda;
				if (WSAStartup(MAKEWORD(2, 2), &wsda) != 0)
				{
					DF_ERR(tt_("WSAStartup failed"));
					return false;
				}
				no = false;
			}
#else
			//防止系统收到SIGPIPE信号终止进程
			signal(SIGPIPE, SIG_IGN);
#endif
			return true;
		}

	};
}
